﻿using System.Text;
using fCloud.SensorApi.Models;
using InfluxDB.Client;
using InfluxDB.Client.Api.Domain;
using InfluxDB.Client.Writes;


namespace fCloud.SensorApi.Services;

public class InfluxDbService : IInfluxDbService
{
   private readonly InfluxDBClient _client = null!;
   private readonly ILogger<IInfluxDbService> _logger=null!;
   private readonly IConfiguration _config=null!;

   public InfluxDbService(InfluxDBClient client,ILogger<IInfluxDbService> logger,IConfiguration config) 
   {
      _client = client;
      _config = config;
      _logger = logger;
      // 异步验证连接（非阻塞）
      _ = CheckConnectionAsync();
   }
   private async Task CheckConnectionAsync()
   {
      try
      {
         var isConnected = await _client.PingAsync();
         _logger.LogInformation(isConnected 
            ? "InfluxDB 连接成功" 
            : "InfluxDB 连接失败");
      }
      catch (Exception ex)
      {
         _logger.LogError(ex, "InfluxDB 连接验证异常");
      }
   }
   public string BuildFluxQuery(
      string measurement,
      string? sensorSn = null,
      List<string>? fields = null,
      DateTime? startTime = null,
      DateTime? endTime = null)
   {
      var start = startTime?.ToUniversalTime() ?? DateTime.UtcNow.AddHours(-24);
      var stop = endTime?.ToUniversalTime() ?? DateTime.UtcNow;

      var flux = new StringBuilder();
      flux.AppendLine($"from(bucket: \"{_config["InfluxDb:Bucket"]}\")");
      flux.AppendLine($"  |> range(start: {start:yyyy-MM-ddTHH:mm:ssZ}, stop: {stop:yyyy-MM-ddTHH:mm:ssZ})");
      flux.AppendLine($"  |> filter(fn: (r) => r._measurement == \"{measurement}\")");

      if (!string.IsNullOrEmpty(sensorSn))
      {
         flux.AppendLine($"  |> filter(fn: (r) => r.sensor_sn == \"{sensorSn}\")");
      }

      if (fields is { Count: > 0 })
      {
         var fieldConditions = string.Join(" or ", fields.Select(f => $"r._field == \"{f}\""));
         flux.AppendLine($"  |> filter(fn: (r) => {fieldConditions})");
      }

      flux.AppendLine("  |> aggregateWindow(every: 1h, fn: mean)");
      return flux.ToString();
   }


   public void WriteDataAsync(SensorData sensorData)
   {
      try
      {
         var point = PointData
         .Measurement("sensordatas")
         .Tag("sensor_sn", sensorData.SensorSn)
         .Tag("device_code", sensorData.DeviceCode)
         .Tag("device_name", sensorData.DeviceName)
         .Field("temper", sensorData.Temper)
         .Field("dens", sensorData.Dens)
         .Field("vis", sensorData.Vis)
         .Field("vis40", sensorData.Vis40)
         .Field("diel", sensorData.Diel)
         .Field("ppm", sensorData.Ppm)
         .Field("aw", sensorData.Aw)
         .Field("mo", sensorData.Mo)
         .Field("par1", sensorData.Par1)
         .Field("par2", sensorData.Par2)
         .Field("par3", sensorData.Par3)
         .Field("par4", sensorData.Par4)
         .Field("par5", sensorData.Par5)
         .Field("par6", sensorData.Par6)
         .Field("par7", sensorData.Par7)
         .Field("par8", sensorData.Par8)
         .Field("class1", sensorData.Class1)
         .Field("class2", sensorData.Class2)
         .Field("class3", sensorData.Class3)
         .Field("class4", sensorData.Class4)
         .Field("class5", sensorData.Class5)
         .Field("class6", sensorData.Class6)
         .Field("fe1", sensorData.Fe1)
         .Field("fe2", sensorData.Fe2)
         .Field("fe3", sensorData.Fe3)
         .Field("fe4", sensorData.Fe4)
         .Field("fe5", sensorData.Fe5)
         .Field("fe6", sensorData.Fe6)
         .Field("fe7", sensorData.Fe7)
         .Field("fe8", sensorData.Fe8)
         .Field("nfe1", sensorData.NFe1)
         .Field("nfe2", sensorData.NFe2)
         .Field("nfe3", sensorData.NFe3)
         .Field("nfe4", sensorData.NFe4)
         .Field("nfe5", sensorData.NFe5)
         .Field("fe", sensorData.Fe)
         .Field("nfe", sensorData.NFe)
         .Field("state", sensorData.State)
         .Field("press", sensorData.Press)
         .Field("speed", sensorData.Speed)
         .Timestamp(sensorData.CreateTime.ToUniversalTime(), WritePrecision.Ns);
         using var writeApi = _client.GetWriteApi();
         writeApi.WritePoint(point);
      }
      catch (Exception e)
      {
         //logger.LogError(ex, "Redis操作失败 Key:{Key}", key);
         _logger.LogError(e,"Influxdb写入错误:{message}",e.Message);
      }
      
   }

   public async Task<SensorHistoryDto> GetPointsAsync(
      string measurement,
      string tag,
      string field,
      DateTime? startTime=null,
      DateTime? endTime=null)
   {
      try
      {
         var queryField = new List<string>() { field };
         var query = BuildFluxQuery("sensordatas", tag, queryField);

         var queryApi = _client.GetQueryApi();
         var tables = await queryApi.QueryAsync(query);
         var result = new SensorHistoryDto();

         foreach (var table in tables)
         {
            foreach (var record in table.Records)
            {
               // 提取 sensorSn
               var sensorSn = record.GetValueByKey("sensor_sn")?.ToString() ?? "unknown";
               result.SensorSn ??= sensorSn;
               result.Field ??= field;

               // 时间戳转字符串
               var time = record.GetTime()?.ToDateTimeUtc().ToString("yyyy-MM-dd HH:mm:ss");

               if (time == null) continue;

               // 提取值
               var value = record.GetValue() is not null 
                  ? Convert.ToDouble(record.GetValue()) 
                  : -99999;

               // 添加到列表
               result.Time.Add(time);
               result.Values.Add(value);
            }
         }

         return result;

      }
      catch (Exception e)
      {
         _logger.LogError(e, "Influxdb查询错误:{message}", e.Message);
         return new SensorHistoryDto() ;
      }
   }
}

public interface IInfluxDbService
{
   public void WriteDataAsync(SensorData sensorData);

   public Task<SensorHistoryDto>
      GetPointsAsync(string measurement,string tag,string field, DateTime? startTime = null, DateTime? endTime = null);
}